package main;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintStream;

import jouetteFrame.FrameImpl;
import parser.impl.MiniJavaParser;
import syntaxtree.Program;
import translate.Frag;
import translate.ProcFrag;
import tree.StmList;
import visitor.SymbolTableCreatorVisitor;
import visitor.SymbolTableTypeCheckVisitor;
import visitor.TranslateToIRVisitor;
import canon.Canon;

public final class MiniJavaCompiler {

	private MiniJavaCompiler() {
	}

	public static void main(String args[]) {
		System.out.println("\n--- Mini Java Compiler ---");

		if (args.length == 1) {
			if ("-test".equals(args[0])) {
				MiniJavaTest.run();
			} else {
				File file = new File(args[0]);
				try {
					FileInputStream fileInputStream = new java.io.FileInputStream(file);
					System.out.println("Reading file " + file.getName() + " from " + file.getAbsolutePath() + ".");
					compile(file.getPath(), fileInputStream);
				} catch (FileNotFoundException e) {
					System.out.println("File " + file.getAbsolutePath() + " not found.");
					return;
				}
			}
		} else {
			System.out.println("Usage is one of:");
			System.out.println("         java main.MiniJavaCompiler minijava_program_source.java");
			return;
		}
	}

	public static void compile(String fileName, InputStream inputStream) {
		try {
			final MiniJavaParser miniJavaParser = new MiniJavaParser(inputStream);
			System.out.print("=> Mini Java Parser: ");
			final Program program = miniJavaParser.Program();
			System.out.println("ok");

			// System.out.print("=> DepthFirstVisitor: ");
			// new DepthFirstVisitor().visit(program);
			// System.out.println("ok");

			// System.out.print("=> TypeDepthFirstVisitor: ");
			// new TypeDepthFirstVisitor().visit(program);
			// System.out.println("ok");

			System.out.print("=> Symbol Table Creator Visitor: ");
			SymbolTableCreatorVisitor symTableVisitor = new SymbolTableCreatorVisitor();
			symTableVisitor.visit(program);
			if (!symTableVisitor.error.anyErrors) {
				System.out.println("ok");
			} else {
				throw new Exception();
			}

			System.out.print("=> Type Check Visitor: ");
			SymbolTableTypeCheckVisitor symTableTypeCheckVisitor = new SymbolTableTypeCheckVisitor(symTableVisitor.programTable);
			symTableTypeCheckVisitor.visit(program);
			if (!symTableTypeCheckVisitor.error.anyErrors) {
				System.out.println("ok");
			} else {
				throw new Exception();
			}

			// System.out.println("=> PrettyPrintVisitor: ");
			// new PrettyPrintVisitor().visit(program);

			System.out.print("=> Translate To IR Visitor: ");
			FrameImpl frameImpl = new FrameImpl();
			TranslateToIRVisitor createIRVisitor = new TranslateToIRVisitor(symTableVisitor.programTable, frameImpl);
			createIRVisitor.visit(program);
			System.out.println("ok");
			final ProcFrag procFragLinkedList = createIRVisitor.procFrag;

			// Cria o arquivo de saída:
			String outputFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".mjc";
			PrintStream compiledFile = new PrintStream(outputFileName);
			Frag procFragTemp = procFragLinkedList;
			do {
				procFragTemp.print(compiledFile);
			} while ((procFragTemp = procFragTemp.next) != null);
			compiledFile.flush();
			compiledFile.close();

			System.out.print("=> Canonicalization: ");
			StmList canonStmList = Canon.generateCode(Canon.generateCode(procFragLinkedList));
			System.out.println("ok");

			System.out.print("=> Instruction Selection: ");
			// List<Instr> listInstr = frameImpl.codegen(canonStmList);
			System.out.println("ok");

			System.out.println("Output file \"" + outputFileName + "\" created successfully.");
			System.out.println();
			System.out.println("MiniJava program compiled successfully.");
		} catch (Exception e) {
			System.out.println("The Mini Java Compiler encountered an error.");
			e.printStackTrace();
		}
	}
}